<template>
  <div class="json-tree-editor-container">
    <div class="editor-header">
      <el-button-group>
        <el-button @click="switchToTree" size="small" :type="viewMode === 'tree' ? 'primary' : ''">
          <el-icon><Collection /></el-icon>
          树形视图
        </el-button>
        <el-button @click="switchToRaw" size="small" :type="viewMode === 'raw' ? 'primary' : ''">
          <el-icon><Document /></el-icon>
          原始视图
        </el-button>
        <el-button @click="formatJson" :disabled="!modelValue" size="small">
          <el-icon><MagicStick /></el-icon>
          格式化
        </el-button>
        <el-button @click="compressJson" :disabled="!modelValue" size="small">
          <el-icon><Files /></el-icon>
          压缩
        </el-button>
        <el-button @click="validateJson" :disabled="!modelValue" size="small">
          <el-icon><Check /></el-icon>
          验证
        </el-button>
      </el-button-group>
      <div class="status-indicator" :class="{ 'valid': isValid, 'invalid': !isValid && modelValue }">
        {{ statusText }}
      </div>
    </div>
    
    <div v-if="viewMode === 'tree'" class="tree-view">
      <div v-if="treeData" class="json-tree">
        <TreeNode 
          :data="treeData" 
          :expanded="true"
          @update-value="handleTreeUpdate"
        />
      </div>
      <div v-else class="empty-tree">
        暂无数据
      </div>
    </div>
    
    <div v-else class="editor-wrapper" :class="{ 'error': hasError }">
      <textarea
        ref="textareaRef"
        v-model="inputValue"
        :placeholder="placeholder"
        @input="handleInput"
        @blur="handleBlur"
        class="json-editor"
      />
    </div>
    
    <div v-if="errorMessage" class="error-message">
      {{ errorMessage }}
    </div>
    
    <div v-if="infoMessage" class="info-message">
      {{ infoMessage }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { Collection, Document, MagicStick, Files, Check } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import TreeNode from './TreeNode.vue'

// 定义组件属性
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  placeholder: {
    type: String,
    default: '请输入JSON内容...'
  },
  height: {
    type: [Number, String],
    default: 300
  },
  readonly: {
    type: Boolean,
    default: false
  }
})

// 定义事件
const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'valid', isValid: boolean): void
  (e: 'change', value: string): void
}>()

// 响应式数据
const inputValue = ref(props.modelValue)
const isValid = ref(true)
const hasError = ref(false)
const errorMessage = ref('')
const infoMessage = ref('')
const textareaRef = ref<HTMLTextAreaElement | null>(null)
const viewMode = ref<'tree' | 'raw'>('tree')
const treeData = ref<any>(null)

// 计算属性
const statusText = computed(() => {
  if (!inputValue.value) return '等待输入'
  return isValid.value ? 'JSON有效' : 'JSON无效'
})

// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
  if (newVal !== inputValue.value) {
    inputValue.value = newVal
    validateJsonString(newVal)
    updateTreeData(newVal)
  }
})

// 处理输入事件
const handleInput = () => {
  emit('update:modelValue', inputValue.value)
  emit('change', inputValue.value)
  validateJsonString(inputValue.value)
  updateTreeData(inputValue.value)
}

// 处理失去焦点事件
const handleBlur = () => {
  // 可以在这里添加额外的处理逻辑
}

// 验证JSON字符串
const validateJsonString = (jsonString: string) => {
  errorMessage.value = ''
  infoMessage.value = ''
  hasError.value = false
  isValid.value = true
  
  if (!jsonString.trim()) {
    isValid.value = true
    emit('valid', true)
    return
  }
  
  try {
    JSON.parse(jsonString)
    isValid.value = true
    emit('valid', true)
  } catch (error: any) {
    isValid.value = false
    hasError.value = true
    errorMessage.value = `JSON格式错误: ${error.message}`
    emit('valid', false)
  }
}

// 更新树形数据
const updateTreeData = (jsonString: string) => {
  if (!jsonString.trim()) {
    treeData.value = null
    return
  }
  
  try {
    const parsed = JSON.parse(jsonString)
    treeData.value = convertToTreeData(parsed, 'root')
  } catch (error) {
    treeData.value = null
  }
}

// 将JSON对象转换为树形数据结构
const convertToTreeData = (data: any, key: string, path: string = ''): any => {
  const nodePath = path ? `${path}.${key}` : key
  
  if (data === null) {
    return {
      key,
      type: 'null',
      value: null,
      path: nodePath
    }
  }
  
  if (Array.isArray(data)) {
    return {
      key,
      type: 'array',
      value: data.map((item, index) => convertToTreeData(item, index.toString(), nodePath)),
      path: nodePath,
      expanded: false
    }
  }
  
  if (typeof data === 'object') {
    return {
      key,
      type: 'object',
      value: Object.keys(data).map(k => convertToTreeData(data[k], k, nodePath)),
      path: nodePath,
      expanded: false
    }
  }
  
  return {
    key,
    type: typeof data,
    value: data,
    path: nodePath
  }
}

// 处理树形节点更新
const handleTreeUpdate = (path: string, value: any) => {
  // 这里可以处理节点值的更新
  console.log('节点更新:', path, value)
}

// 切换到树形视图
const switchToTree = () => {
  viewMode.value = 'tree'
  updateTreeData(inputValue.value)
}

// 切换到原始视图
const switchToRaw = () => {
  viewMode.value = 'raw'
}

// 格式化JSON
const formatJson = () => {
  if (!inputValue.value.trim()) {
    ElMessage.warning('没有内容可格式化')
    return
  }
  
  try {
    const parsed = JSON.parse(inputValue.value)
    inputValue.value = JSON.stringify(parsed, null, 2)
    emit('update:modelValue', inputValue.value)
    ElMessage.success('JSON已格式化')
    infoMessage.value = 'JSON已成功格式化'
    setTimeout(() => {
      infoMessage.value = ''
    }, 3000)
    updateTreeData(inputValue.value)
  } catch (error: any) {
    ElMessage.error('JSON格式错误，无法格式化')
    errorMessage.value = `格式化失败: ${error.message}`
  }
}

// 压缩JSON
const compressJson = () => {
  if (!inputValue.value.trim()) {
    ElMessage.warning('没有内容可压缩')
    return
  }
  
  try {
    const parsed = JSON.parse(inputValue.value)
    inputValue.value = JSON.stringify(parsed)
    emit('update:modelValue', inputValue.value)
    ElMessage.success('JSON已压缩')
    infoMessage.value = 'JSON已成功压缩'
    setTimeout(() => {
      infoMessage.value = ''
    }, 3000)
    updateTreeData(inputValue.value)
  } catch (error: any) {
    ElMessage.error('JSON格式错误，无法压缩')
    errorMessage.value = `压缩失败: ${error.message}`
  }
}

// 验证JSON
const validateJson = () => {
  if (!inputValue.value.trim()) {
    ElMessage.info('没有内容可验证')
    return
  }
  
  try {
    JSON.parse(inputValue.value)
    ElMessage.success('JSON格式正确')
    infoMessage.value = 'JSON格式验证通过'
    setTimeout(() => {
      infoMessage.value = ''
    }, 3000)
  } catch (error: any) {
    ElMessage.error('JSON格式错误')
    errorMessage.value = `验证失败: ${error.message}`
  }
}

// 在组件挂载时验证初始值
onMounted(() => {
  if (inputValue.value) {
    validateJsonString(inputValue.value)
    updateTreeData(inputValue.value)
  }
})

// 暴露方法给父组件
defineExpose({
  formatJson,
  compressJson,
  validateJson
})
</script>

<style scoped>
.json-tree-editor-container {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
}

.editor-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #dcdfe6;
}

.status-indicator {
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 4px;
  color: #909399;
}

.status-indicator.valid {
  background-color: #f0f9eb;
  color: #67c23a;
}

.status-indicator.invalid {
  background-color: #fef0f0;
  color: #f56c6c;
}

.tree-view {
  min-height: 300px;
  max-height: 500px;
  overflow-y: auto;
  background-color: #fafafa;
}

.editor-wrapper {
  position: relative;
}

.editor-wrapper.error {
  border-color: #f56c6c;
}

.json-editor {
  width: 100%;
  min-height: 300px;
  padding: 12px;
  border: none;
  outline: none;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 14px;
  line-height: 1.5;
  resize: vertical;
  background-color: #fafafa;
}

.json-editor:focus {
  background-color: #fff;
}

.empty-tree {
  padding: 20px;
  text-align: center;
  color: #909399;
}

.error-message {
  padding: 8px 12px;
  background-color: #fef0f0;
  color: #f56c6c;
  font-size: 12px;
  border-top: 1px solid #fde2e2;
}

.info-message {
  padding: 8px 12px;
  background-color: #f0f9eb;
  color: #67c23a;
  font-size: 12px;
  border-top: 1px solid #e1f3d8;
}
</style>